#!/usr/bin/env python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

# Copyright (c) 2019-2020 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated DocTemplation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import os
import asyncio
from playwright.async_api import async_playwright
from .manpa_util import ManpaUtil


class ManpaPlaywrightClient:

    def __init__(self, parent):
        self._parent = parent
        self._parent._playwrightClientList.append(self)

        self._playwright = None
        self._browser = None
        self._context = None
        self._page = None
        try:
            # select User-Agent
            ua = ManpaUtil.getRandomUserAgent()

            # initialize playwright
            asyncio.get_event_loop().run_until_complete(self._init_browser(ua))
        except Exception:
            self.dispose()
            raise

    def dispose(self):
        asyncio.get_event_loop().run_until_complete(
            self._dispose()
        )

    async def _init_browser(self, ua):
        self._playwright = await async_playwright().start()

        # Set up browser options
        browser_options = {
            "args": [
                '--no-sandbox',
                '--ignore-ssl-error=yes',
                '--ignore-certificate-errors',
                '--disable-popup-blocking',
                '--no-default-browser-check'
            ]
        }

        if not self._parent._isDebug:
            browser_options["args"].append("--headless=new")

        if len(self._parent._proxyList) > 0:
            browser_options["proxy"] = {
                "server": self._parent._proxyList[0]  # FIXME: get random proxy
            }

        # Create browser context with video recording
        context_options = {
            "user_agent": ua,
            "viewport": {
                "width": self._parent._width,
                "height": self._parent._height
            },
            "ignore_https_errors": True,
            "downloads_path": self._parent._tmpDownloadDir,
        }

        # Add video recording if enabled
        if self._parent._videoLogFile is not None:
            context_options.update({
                "record_video_dir": os.path.dirname(self._parent._videoLogFile),
                "record_video_size": {
                    "width": self._parent._width,
                    "height": self._parent._height
                },
            })

        self._browser = await self._playwright.chromium.launch(**browser_options)
        self._context = await self._browser.new_context(**context_options)
        self._page = await self._context.new_page()

    async def _dispose(self):
        if self._parent._videoLogFile is not None:
            # save video
            await self._page.video.path()
            self._page = None

        if self._context is not None:
            await self._context.close()
            self._context = None

        if self._browser is not None:
            await self._browser.close()
            self._browser = None

        if self._playwright is not None:
            await self._playwright.stop()
            self._playwright = None

        if True:
            self._parent._playwrightClientList.remove(self)
            self._parent = None

    def __getattr__(self, attr):
        return getattr(self._page, attr)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self.dispose()
